﻿using DryIoc;
using EONFULLSIN2.Core;
using EONFULLSIN2.Core.Extensions;
using EONFULLSIN2.Models.Attributes;
using EONFULLSIN2.Models.Dto.Device;
using EONFULLSIN2.Models.Enum;
using EONFULLSIN2.Models.Enum.IOPointEnum;
using EONFULLSIN2.Services.Device;
using ImTools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;

namespace EONFULLSIN2.Services.Device.ZMoiton {

    /// <summary>
    /// 务必注册成单例
    /// </summary>
    public class ZMoitonService : IZMoitonService {

        //private static readonly Lazy<ZMoitonModbusService> zMoitonModbusService = new Lazy<ZMoitonModbusService>(() => new ZMoitonModbusService());

        /// <summary>
        /// 上位机扫描周期，单位ms
        /// </summary>
        private const int _scanCycle_UpPC = 1000;
        /// <summary>
        /// 下位机扫描周期，单位ms
        /// </summary>
        private const int _scanCycle_DownPC = 1100;

        private bool _doHeart = true;

        private int timeOut;

        private IntPtr g_handle; // 链接返回的句柄，可以作为卡号

        public ZMoitonService() {
            this.IOPoints = Enum.GetValues(typeof(eIOPointEnum))
                            .Cast<eIOPointEnum>()
                            .ToList();
        }

        public string IpAddress { private set; get; } = "192.168.1.11";

        public int Port { private set; get; }

        public bool IsConnect { private set; get; }

        public List<eIOPointEnum> IOPoints { protected set; get; }

        public async Task<bool> ConnectAsync() {
            if (IsConnect) {
                return false;
            }

            // 建立连接
            var res = await Task.Factory.StartNew(() => {
                int iresult = Zmcaux.ZAux_FastOpen(2, IpAddress, 1000, out g_handle);
                IsConnect = (iresult == 0);
                return iresult == 0;
            });

            #region 心跳机制
            if (res) {
                // 设置心跳参数
                var ret = Zmcaux.ZAux_Direct_SetUserVar(g_handle, "Heart_Time", _scanCycle_DownPC);
                //设置心跳输出点个数
                ret = Zmcaux.ZAux_Direct_SetUserVar(g_handle, "Heart_OutNum", 16);
                // 启动心跳
                ret = Zmcaux.ZAux_Direct_SetUserVar(g_handle, "Heart_StarFlag", 1);
                _doHeart = true;
                _ = Task.Run(async () => {
                    while (_doHeart) {
                        ret = Zmcaux.ZAux_Direct_SetUserVar(g_handle, "Heart_Status", 0);
                        if (ret != 0)
                            timeOut++;
                        else
                            timeOut = 0;
                        if (timeOut > 1) {
                            continue;
                        }
                        await Task.Delay(_scanCycle_UpPC);
                    }
                    LogManager.Debug("退出心跳写入！");
                });
            }
            #endregion

            return res;
        }

        public Task<bool> DisConnectAsync() {
            bool bresult = Zmcaux.ZAux_Close(g_handle) == 0;  // 假设此方法是同步的
            if (bresult) {
                g_handle = (IntPtr)0;         // 重置句柄
                IsConnect = false;            // 更新连接状态
                _doHeart = false;
            }
            return Task.FromResult(bresult);  // 返回已完成的 Task
        }


        public Task<List<SensorItemDto>> GetSensorOutPutStatusAsync() {
            List<SensorItemDto> channelStatusList = new List<SensorItemDto>();
            if (IsConnect) {
                uint[] iostateOutPut = new uint[16];
                bool bresult = Zmcaux.ZAux_Direct_GetOutMulti(g_handle, 0, (16 - 1), iostateOutPut) == 0;
                if (bresult) {

                    for (int i = 0; i < iostateOutPut.Length; i++) {
                        bool status = ((iostateOutPut[0] & 1 << i) != 0 ? true : false);
                        var iOPointType = IOPoints.FirstOrDefault(o => o.GetAttributeOfType<IOPointAttribute>().ChannelIndex == i);
                        var attr = iOPointType.GetAttributeOfType<IOPointAttribute>();
                        var value = new SensorItemDto() {
                            ID = attr.ChannelIndex,
                            Name = attr.ChannelName,
                            CodeNumber = attr.Name,
                            Description = attr.Description,
                            Type = eSensorTypeEnum.IOMdoel,
                            DataSourceAddress = iOPointType,
                            IsEnable = attr.IsEnable,
                            Value = status,
                        };
                        channelStatusList.Add(value);
                    }
                }
            }
            return Task.FromResult(channelStatusList);  // 返回已完成的 Task
        }

        public Task<bool?> GetSensorOutPutStatusByIndexAsync(eIOPointEnum eIOPointEnum) {
            bool? bresult = default;
            if (IsConnect) {
                var index = eIOPointEnum.GetAttributeOfType<IOPointAttribute>().ChannelIndex;
                uint[] iostateOutPut = new uint[1];
                var res = Zmcaux.ZAux_Direct_GetOutMulti(g_handle, (ushort)index, (ushort)(index + 1), iostateOutPut) == 0;
                if (res) {
                    bresult = ((iostateOutPut[0] & 1 << 0) != 0 ? true : false);
                }
            }
            return Task.FromResult(bresult);  // 返回已完成的 Task
        }

        public Task<bool> SetOutPutStatusByIndexAsync(eIOPointEnum eIOPointEnum, bool value) {
            bool bresult = false;
            if (IsConnect) {
                var index = eIOPointEnum.GetAttributeOfType<IOPointAttribute>().ChannelIndex;
                var res = Zmcaux.ZAux_Direct_SetOp(g_handle, index, value ? (uint)1 : 0);
                bresult = res == (0);
            }
            return Task.FromResult(bresult);  // 返回已完成的 Task
        }
    }

}
